/**
 * @name utils.js
 * @description 基本工具函数
 * @author 'fwq'
 * @time 2021/10/17
 */
import {
  camelize,
  capitalize,
  extend,
  hasOwn,
  hyphenate,
  isArray,
  isObject,
  isPlainObject,
  isString,
  looseEqual,
  toRawType,
} from "@vue/shared";

const getStyle = (style, filter = []) => {
  const noNeedUnit = [
    "color",
    "backgroundColor",
    "textAlign",
    "opacity",
    "lineHeight",
    "fontWeight",
    "borderColor",
    "font-family"
  ];
  const result = {};
  Object.keys(style).forEach((key) => {
    if (!filter.includes(key)) {
      if (key != "rotate") {
        result[key] = style[key];
        if (!noNeedUnit.includes(key)) {
          result[key] += "px";
        }
      } else {
        result.transform = key + "(" + style[key] + "deg)";
      }
    }
  });
  return result;
};

function debounce(func, wait, immediate) {
  let time;
  let debounced = function () {
    let context = this;
    if (time) clearTimeout(time);

    if (immediate) {
      let callNow = !time;
      if (callNow) func.apply(context, arguments);
      time = setTimeout(
        () => {
          time = null;
        } //见注解
        , wait);
    } else {
      time = setTimeout(
        () => {
          func.apply(context, arguments);
        }
        , wait);
    }
  };

  debounced.cancel = function () {
    clearTimeout(time);
    time = null;
  };

  return debounced;
}

function LoadStyle(url) {
  let head = document.getElementsByTagName("head")[0];
  let link = document.createElement("link");
  link.type = "text/css";
  link.rel = "stylesheet";
  link.href = url;
  head.appendChild(link);
}

function UUID2(len, radix) {
  let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");
  let uuid = [], i;
  radix = radix || chars.length;
  if (len) {
    // Compact form
    for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
  } else {
    // rfc4122, version 4 form
    let r;
    // rfc4122 requires these characters
    uuid[8] = uuid[13] = uuid[18] = uuid[23] = "-";
    uuid[14] = "4";
    // Fill in random data.  At i==19 set the high bits of clock sequence as
    // per rfc4122, sec. 4.1.5
    for (i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = 0 | Math.random() * 16;
        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
      }
    }
  }

  return uuid.join("");
}

function observerDomResize(dom, callback) {
  const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  const observer = new MutationObserver(callback);
  observer.observe(dom, { attributes: true, attributeFilter: ["style"], attributeOldValue: true });

  return observer;
}

function getCircleRadianPoint(x, y, radius, radian) {
  return [x + Math.cos(radian) * radius, y + Math.sin(radian) * radius];
}

const cloneDeep = (value, hash = new WeakMap()) => {
  if (value == null) return value;
  if (typeof value !== "object") return value;
  if (value instanceof RegExp) return new RegExp(value);
  if (value instanceof Date) return new Date(value);

  let instance = new value.constructor();
  if (hash.has(value)) {
    // 先去hash中查看一下是否存在过 ，如果存在就把以前拷贝的返回去
    return hash.get(value);
  }
  hash.set(value, instance); // 没放过就放进去
  for (let key in value) {
    instance[key] = cloneDeep(value[key], hash);
  }
  return instance;
};

function mergeDeep(target, ...arg) {
  return arg.reduce((acc, cur) => {
    return Object.keys(cur).reduce((subAcc, key) => {
      const srcVal = cur[key];
      if (isObject(srcVal)) {
        subAcc[key] = merge(subAcc[key] ? subAcc[key] : {}, srcVal);
      } else if (isArray(srcVal)) {
        // series: []，下层数组直接赋值
        subAcc[key] = srcVal.map((item, idx) => {
          if (isObject(item)) {
            const curAccVal = subAcc[key] ? subAcc[key] : [];
            return merge(curAccVal[idx] ? curAccVal[idx] : {}, item);
          } else {
            return item;
          }
        });
      } else {
        subAcc[key] = srcVal;
      }
      return subAcc;
    }, acc);
  }, target);
}

function randomExtend(minNum, maxNum) {
  if (arguments.length === 1) {
    return parseInt(Math.random() * minNum + 1, 10);
  } else {
    return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
  }
}

function filterNonNumber(array) {
  return array.filter(function (n) {
    return typeof n === "number";
  });
}

function mulAdd(nums) {
  nums = filterNonNumber(nums);
  return nums.reduce(function (all, num) {
    return all + num;
  }, 0);
}

function getTwoPointDistance(pointOne, pointTwo) {
  const minusX = Math.abs(pointOne[0] - pointTwo[0]);
  const minusY = Math.abs(pointOne[1] - pointTwo[1]);
  return Math.sqrt(minusX * minusX + minusY * minusY);
}

function getPolylineLength(points) {
  let lineSegments = new Array(points.length - 1).fill(0).map(function (foo, i) {
    return [points[i], points[i + 1]];
  });
  let lengths = lineSegments.map(function (item) {
    return getTwoPointDistance.apply(undefined, item);
  });
  return mulAdd(lengths);
}

/**
 * 获取字符串中 :value 形式的参数
 */
const getTextParams = (text) => {
  const reg = /:([\d\w\u4e00-\u9fa5_$@*]+)/ig;
  return text.match(reg) ?? [];
};

/**
 * 深合并对象
 * @param obj1
 * @param obj2
 */
export const DeepMerge = function (obj1, obj2) {
  let key;
  for (key in obj2) {
    // 如果target(也就是obj1[key])存在，且是对象的话再去调用deepMerge，否则就是obj1[key]里面没这个对象，需要与obj2[key]合并
    obj1[key] = obj1[key] && obj1[key].toString() === "[object Object]" ?
      DeepMerge(obj1[key], obj2[key]) : obj1[key] = obj2[key];
  }
  return obj1;
};

/**
 * 生成id
 * @returns {string}
 * @constructor
 */
const GenerateID = function () {
  function S4() {
    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  }

  return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
};

const copyText = (text) => {
  try {
    const input = document.createElement("textarea");
    input.value = text;
    document.body.appendChild(input);
    input.select();
    document.execCommand("copy");
    document.body.removeChild(input);
    return true;
  } catch (error) {
    return false;
  }
};

function saveJSON(data, filename) {
  if (!data) {
    alert("保存的数据为空");
    return;
  }
  if (!filename)
    filename = "json.json";
  if (typeof data === "object") {
    data = JSON.stringify(data, undefined, 4);
  }
  let blob = new Blob([data], { type: "text/json" }),
    e = document.createEvent("MouseEvents"),
    a = document.createElement("a");
  a.download = filename;
  a.href = window.URL.createObjectURL(blob);
  a.dataset.downloadurl = ["text/json", a.download, a.href].join(":");
  e.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  a.dispatchEvent(e);
}

const nodeTree = function (list) {
  let result = [],
    nodeObj = {};
  for (let node = 0; node < list.length; node++) {
    nodeObj[list[node].from] = list[node]; //将nodes数组转成对象类型
  }
  for (let j = 0; j < list.length; j++) {
    let nodeParentObj = nodeObj[list[j].to]; //获取每一个子对象的父对象
    if (nodeParentObj) {
      //判断父对象是否存在，如果不存在直接将对象放到第一层
      if (!nodeParentObj["children"]) nodeParentObj["children"] = []; //如果父元素的children对象不存在，则创建数组
      nodeParentObj["children"].push(list[j]); //将本对象压入父对象的nodes数组
    } else {
      result.push(list[j]); //将不存在父对象的对象直接放入一级目录
    }
  }
  return result;
};
export {
  getStyle,
  debounce,
  LoadStyle,
  UUID2,
  observerDomResize,
  mergeDeep,
  cloneDeep,
  randomExtend,
  getPolylineLength,
  getCircleRadianPoint,
  getTextParams,
  GenerateID,
  copyText,
  saveJSON,
  nodeTree,
  isObject,
  isPlainObject,
  isArray,
  isString,
  capitalize,
  hyphenate,
  looseEqual,
  extend,
  camelize,
  hasOwn,
  toRawType,
};
